﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Web.Security;
using WpfMembershipAdmin.Properties;
using System.Diagnostics;
using Microsoft.Win32;

namespace WpfMembershipAdmin
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void ShowError(Exception ex)
        {
            //ErrorDetailWindow.BuildErrorDetailWindow(this, ex).ShowDialog();
            MessageBox.Show(ex.Message);
        }

        #region Role Management

        private void RefreshRoleTree()
        {
            mainTreeView.Items.Clear();

            TreeViewItem rootItem = new TreeViewItem()
            {
                Header = Properties.Resources.Role_All
            };
            rootItem.Selected += new RoutedEventHandler(RootItem_Selected);

            String[] allRoles = Roles.GetAllRoles();
            foreach (String r in allRoles)
            {
                TreeViewItem tvi = new TreeViewItem()
                {
                    Header = r
                };
                tvi.Selected += new RoutedEventHandler(TreeViewItem_Selected);
                rootItem.Items.Add(tvi);
            }

            mainTreeView.Items.Add(rootItem);

            rootItem.IsExpanded = true;
        }

        private IEnumerator<String> EnumerateAllUsers()
        {
            MembershipUserCollection allUsers = Membership.GetAllUsers();
            foreach (MembershipUser u in allUsers)
            {
                yield return u.UserName;
            }
        }

        private IEnumerator<String> EnumerateRole(String roleName)
        {
            if (Roles.RoleExists(roleName))
            {
                String[] users = Roles.GetUsersInRole(roleName);
                foreach (String u in users)
                {
                    yield return u;
                }
            }
        }

        private void ShowUserResults(IEnumerator<String> userResults)
        {
            this.resultsListView.Items.Clear();
            while (userResults.MoveNext())
            {
                ListViewItem lvi = new ListViewItem()
                {
                    Content = userResults.Current
                };

                lvi.MouseDoubleClick += new MouseButtonEventHandler(ListViewItem_MouseDoubleClick);

                this.resultsListView.Items.Add(lvi);
            }
        }

        void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            try
            {
                ListViewItem doubleClickedItem = e.Source as ListViewItem;
                if (doubleClickedItem != null)
                {
                    String username = doubleClickedItem.Content as String;
                    if (username != null)
                    {
                        MembershipUser doubleClickedUser = Membership.GetUser(username);
                        if (doubleClickedUser != null)
                        {
                            UserDetailsWindow userDetails = this.BuildOwnedWindowWithTitle<UserDetailsWindow>(doubleClickedUser.UserName);
                            userDetails.DisplayedUser = doubleClickedUser;
                            userDetails.Show();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private void CreateRole(String roleName)
        {
            Roles.CreateRole(roleName);
            RefreshRoleTree();
        }

        private void RemoveRole(String roleName)
        {
            Roles.DeleteRole(roleName);
            RefreshRoleTree();
        }

        #endregion

        internal T BuildOwnedWindowWithTitle<T>(String title)
            where T: Window, new()
        {
            T detailsWindow = new T();
            detailsWindow.Owner = this;
            detailsWindow.Title = title;
            return detailsWindow;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            RefreshRoleTree();
        }

        private void RootItem_Selected(object sender, RoutedEventArgs e)
        {
            try
            {
                IEnumerator<String> userEnum = EnumerateAllUsers();
                ShowUserResults(userEnum);
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
        {
            try
            {
                TreeViewItem tvi = e.Source as TreeViewItem;
                if (tvi != null)
                {
                    String roleName = tvi.Header.ToString();
                    IEnumerator<String> userEnum = EnumerateRole(roleName);
                    ShowUserResults(userEnum);
                }

                e.Handled = true;
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private void AddRole_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                DialogWindow dlg = this.BuildOwnedWindowWithTitle<DialogWindow>(Properties.Resources.Role_Add);
                dlg.SetDisplayValues(Properties.Resources.Role_Label, String.Empty);
                bool? dlgResult = dlg.ShowDialog();

                if (dlgResult.HasValue && dlgResult.Value)
                {
                    String roleName = dlg.textBox1.Text;
                    CreateRole(roleName);
                }
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private void RemoveRole_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                String defaultRoleName = GetSelectedRoleName();

                DialogWindow dlg = this.BuildOwnedWindowWithTitle<DialogWindow>(Properties.Resources.Role_Remove);
                dlg.SetDisplayValues(Properties.Resources.Role_Label, defaultRoleName);
                bool? dlgResult = dlg.ShowDialog();

                if (dlgResult.HasValue && dlgResult.Value)
                {
                    String roleName = dlg.textBox1.Text;
                    RemoveRole(roleName);
                }
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private String GetSelectedRoleName()
        {
            TreeViewItem tvi = mainTreeView.SelectedItem as TreeViewItem;
            String defaultRoleName = (tvi != null) ? tvi.Header.ToString() : String.Empty;
            return defaultRoleName;
        }

        private void AddUser_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                UserCreateWindow newUserDetails = BuildOwnedWindowWithTitle<UserCreateWindow>(Properties.Resources.User_Add);
                newUserDetails.Show();
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private void RemoveUser_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ListViewItem selectedItem = this.resultsListView.SelectedItem as ListViewItem;
                if (selectedItem != null)
                {
                    String selectedUsername = selectedItem.Content as string;
                    bool userSuccessfullyDeleted = Membership.DeleteUser(selectedUsername);

                    if (userSuccessfullyDeleted)
                    {
                        this.resultsListView.Items.Remove(selectedItem);
                    }
                }
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private static String BuildAspNetRegSqlCommand(bool add)
        {
            // TODO: add support for more flags

            String defaultConnectionString = "<connection string>";
            System.Configuration.ConnectionStringSettingsCollection connectionStrings = System.Web.Configuration.WebConfigurationManager.ConnectionStrings;
            if ((connectionStrings != null) && (connectionStrings.Count != 0))
            {
                defaultConnectionString = connectionStrings[0].ConnectionString;
            }

            String aspnetRegSql = Settings.Default.AspNetRegSqlLocation;
            String flag = (add) ? "A" : "R";
            String commandString = String.Format("\"{0}\" -C {1} -{2} all", aspnetRegSql, defaultConnectionString, flag);
            
            return commandString;
        }

        private void PromptWithAspnetCommand(bool addFlag)
        {
            String commandString = BuildAspNetRegSqlCommand(addFlag);
            DialogWindow d = BuildOwnedWindowWithTitle<DialogWindow>(Properties.Resources.Tools_AddFeatures);
            d.SetDisplayValues(Properties.Resources.Tools_ConnectionString, commandString);
            d.btnOk.Content = Properties.Resources.Tools_CopyToClipboard;
            bool? result = d.ShowDialog();
        }

        private void AddDbFeatures_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            PromptWithAspnetCommand(true);
        }

        private void RemoveDbFeatures_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            PromptWithAspnetCommand(false);
        }

        private void GenerateUserPassword_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            String newPassword = Membership.GeneratePassword(
                Settings.Default.PasswordGenerator_Length,
                Settings.Default.PasswordGenerator_NumberOfNonAlphaNumericCharacters);

            DialogWindow d = BuildOwnedWindowWithTitle<DialogWindow>(Properties.Resources.Tools_GeneratePassword);
            d.SetDisplayValues(Properties.Resources.User_PasswordLabel, newPassword);
            d.btnOk.Content = Properties.Resources.Tools_CopyToClipboard;
            bool? result = d.ShowDialog();
            
            if (result.HasValue && result.Value)
            {
                Clipboard.SetData(DataFormats.Text, d.textBox1.Text);
            }
        }

        private void GenerateUserRoleMappingSql_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                DialogWindow dlg = BuildOwnedWindowWithTitle<DialogWindow>(Properties.Resources.Tools_GenerateSqlTitle);
                dlg.SetDisplayValues(Properties.Resources.Tools_GenerateSqlLabel, String.Empty);
                bool? result = dlg.ShowDialog();

                if (result.HasValue && result.Value)
                {
                    String applicationName = dlg.textBox1.Text;

                    SaveFileDialog saveFileDlg = new SaveFileDialog()
                    {
                        Title = Properties.Resources.Tools_GenerateSqlTitle,
                        InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                        CheckPathExists = true,
                        FileName = "generate-user-roles.sql",
                        Filter = "SQL Files (*.sql)|*.sql",
                        FilterIndex = 0
                    };

                    bool? saveFileResult = saveFileDlg.ShowDialog(this);

                    if (saveFileResult.HasValue && saveFileResult.Value)
                    {
                        using (System.IO.Stream fileStream = saveFileDlg.OpenFile())
                        {
                            WriteSqlScript(applicationName, fileStream);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ShowError(ex);
            }
        }

        private static void WriteSqlScript(String applicationName, System.IO.Stream fileStream)
        {
            using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(fileStream, Encoding.UTF8))
            {
                streamWriter.WriteLine("-- Autogenerated from Wpf Membership Console on {0:yyyy/MM/dd HH:mm:ss.zzzz}", DateTime.Now);
                streamWriter.WriteLine();

                streamWriter.WriteLine("declare @dt datetime");
                streamWriter.WriteLine("declare @appname nvarchar(100)");
                streamWriter.WriteLine("set @dt = convert(nvarchar, getutcdate())");
                streamWriter.WriteLine("set @appname = N'{0}'", applicationName);
                streamWriter.WriteLine();

                foreach (String roleName in Roles.GetAllRoles())
                {
                    foreach (String userName in Roles.GetUsersInRole(roleName))
                    {
                        streamWriter.WriteLine("EXEC [aspnet_UsersInRoles_AddUsersToRoles]");
                        streamWriter.WriteLine("\t\t@ApplicationName = @appname,");
                        streamWriter.WriteLine("\t\t@UserNames = N'{0}',", userName);
                        streamWriter.WriteLine("\t\t@RoleNames = N'{0}',", roleName);
                        streamWriter.WriteLine("\t\t@CurrentTimeUtc = @dt");
                        streamWriter.WriteLine();
                    }
                }

                streamWriter.WriteLine();
                streamWriter.WriteLine("GO");
                streamWriter.WriteLine();
            }
        }

    }
}
